package com.quan.mall.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.quan.commons.core.bean.R;
import com.quan.commons.core.biz.support.MyBaseServiceImpl;
import com.quan.commons.core.configuration.LoginUserInterceptor;
import com.quan.commons.core.configuration.WxPayConfiguration;
import com.quan.commons.core.exception.BizException;
import com.quan.commons.core.utils.AmountUtils;
import com.quan.commons.core.utils.OrderUtils;
import com.quan.commons.core.utils.PageUtils;
import com.quan.mall.commons.vo.OmsOrderReturnApplyVo;
import com.quan.mall.entity.*;
import com.quan.mall.mapper.OmsOrderReturnApplyMapper;
import com.quan.mall.service.*;
import com.quan.system.commons.vo.SysUserVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service
public class OmsOrderReturnApplyServiceImpl extends MyBaseServiceImpl<OmsOrderReturnApplyMapper, OmsOrderReturnApply> implements OmsOrderReturnApplyService {

    @Autowired
    private OmsOrderReturnApplyMapper mapper;

    @Autowired
    private OmsOrderService omsOrderService;

    @Autowired
    private OmsOrderGoodsService omsOrderGoodsService;

    @Autowired
    private MallDeliveryAddressService mallDeliveryAddressService;

    @Autowired
    private UmsMemberService umsMemberService;

    @Autowired
    private OmsOrderOperateLogService omsOrderOperateLogService;

    @Autowired
    private PmsSkuService pmsSkuService;

    @Autowired
    private PmsSpuService pmsSpuService;

    @Autowired
    private PmsBrandService pmsBrandService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private FmsFinanceCashFlowService fmsFinanceCashFlowService;

    @Autowired
    private FmsMemberCommisionFreezeService fmsMemberCommisionFreezeService;

    @Autowired
    private WmsWareSkuService wmsWareSkuService;

    @Override
    public List<OmsOrderReturnApplyVo> queryList(PageUtils pageUtils, OmsOrderReturnApplyVo vo) {
        QueryWrapper<OmsOrderReturnApply> queryWrapper = new QueryWrapper<OmsOrderReturnApply>(vo);

        // 查询多个状态，状态用","隔开
        if (StringUtils.isNotBlank(vo.getInStatus())) {
            queryWrapper.in("status", vo.getInStatus().split(","));
        }

        List<OmsOrderReturnApply> list = super.list(pageUtils, queryWrapper);
        List<OmsOrderReturnApplyVo> collect = list.stream().map(item -> {
            OmsOrderReturnApplyVo bean = new OmsOrderReturnApplyVo();
            BeanUtils.copyProperties(item, bean);
            return bean;
        }).collect(Collectors.toList());

        return collect;
    }

    @Override
    public PageUtils queryPage(PageUtils pageUtils, OmsOrderReturnApplyVo vo) {
        QueryWrapper<OmsOrderReturnApply> queryWrapper = new QueryWrapper<OmsOrderReturnApply>(vo);

        if (StringUtils.isNotBlank(vo.getKeyword())) {
            queryWrapper.and(w -> {
                w.like("order_sn", vo.getKeyword())
                        .or().like("member_username", vo.getKeyword());
            });
        }

        // 时间选择->0:今天;1:昨天;2:最近7天;3:最近30天:4:本月;5本年
        if (null != vo.getDateAttr()) {
            if (vo.getDateAttr() == 0) {
                queryWrapper.apply("date_format(ctime, '%Y-%m-%d') >= {0}", LocalDate.now());
            } else if (vo.getDateAttr() == 1) {
                queryWrapper.apply("date_format(ctime, '%Y-%m-%d') >= {0}", LocalDate.now().plusDays(-1));
            } else if (vo.getDateAttr() == 2) {
                queryWrapper.apply("date_format(ctime, '%Y-%m-%d') >= {0} and date_format(ctime, '%Y-%m-%d') <= {1}", LocalDate.now().plusDays(-7), LocalDate.now());
            } else if (vo.getDateAttr() == 3) {
                queryWrapper.apply("date_format(ctime, '%Y-%m-%d') >= {0} and date_format(ctime, '%Y-%m-%d') <= {1}", LocalDate.now().plusDays(-30), LocalDate.now());
            } else if (vo.getDateAttr() == 4) {
                // 本月的第一天
                final LocalDate firstMonthDay = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
                // 本月的最后一天
                final LocalDate lastMonthDay = LocalDate.now().plusYears(1).with(TemporalAdjusters.firstDayOfMonth());
                queryWrapper.apply("date_format(ctime, '%Y-%m-%d') >= {0} and date_format(ctime, '%Y-%m-%d') <= {1}", firstMonthDay, lastMonthDay);
            } else if (vo.getDateAttr() == 5) {
                // 今年的第一天
                final LocalDate firstYearDay = LocalDate.now().with(TemporalAdjusters.firstDayOfYear());
                // 今年的最后一天
                final LocalDate lastYearDay = LocalDate.now().plusYears(1).with(TemporalAdjusters.firstDayOfYear());
                queryWrapper.apply("date_format(ctime, '%Y-%m-%d') >= {0} and date_format(ctime, '%Y-%m-%d') <= {1}", firstYearDay, lastYearDay);
            }
        } else {
            // 下单日期范围
            if (StringUtils.isNotEmpty(vo.getDateRange())) {
                final String[] split = vo.getDateRange().split(",");
                String startDate = split[0];
                String endDate = split[1];
                queryWrapper.apply("date_format(ctime, '%Y-%m-%d') >= {0} and date_format(ctime, '%Y-%m-%d') <= {1}", startDate, endDate);
            }
        }

        final IPage<OmsOrderReturnApply> page = super.selectPage(pageUtils, queryWrapper);

        PageUtils ps = new PageUtils(page);

        final List<OmsOrderReturnApply> records = page.getRecords();

        final List<OmsOrderReturnApplyVo> collect = records.stream().map((item) -> {
            OmsOrderReturnApplyVo bean = new OmsOrderReturnApplyVo();
            BeanUtils.copyProperties(item, bean);
            return bean;
        }).collect(Collectors.toList());

        ps.setRecords(collect);
        return ps;
    }

    @Override
    public OmsOrderReturnApplyVo getOrderReturnApplyInfo(Long id) {
        OmsOrderReturnApplyVo vo = new OmsOrderReturnApplyVo();

        final OmsOrderReturnApply apply = super.getById(id);
        BeanUtils.copyProperties(apply, vo);

        // 会员信息
        final UmsMember member = this.umsMemberService.getById(apply.getMemberId());
        vo.setMember(member);

        // 操作记录信息
        final List<OmsOrderOperateLog> logs = this.omsOrderOperateLogService.list(new QueryWrapper<OmsOrderOperateLog>().eq("order_id", id).orderByDesc("ctime"));
        vo.setLogs(logs);

        return vo;
    }

    @Override
    public void changeReturnStatus(Long id, Integer status) {
        UpdateWrapper updateWrapper = new UpdateWrapper();
        updateWrapper.set("status", status);
        updateWrapper.eq("id", id);
        super.update(updateWrapper);
    }

    @Transactional
    @Override
    public OmsOrderReturnApply apply(OmsOrderReturnApplyVo vo) {

        // 订单信息
        final OmsOrder order = this.omsOrderService.getOrderByOrderSn(vo.getOrderSn());
        // 申请退款商品
        final OmsOrderGoods goods = this.omsOrderGoodsService.getById(vo.getGoodsId());

        final UmsMember umsMember = this.umsMemberService.getById(order.getMemberId());

        // 售后单号
        String postSaleSn = OrderUtils.getSN();

        // 申请退款
        OmsOrderReturnApply apply = new OmsOrderReturnApply();
        apply.setAppId(order.getAppId());
        apply.setMchId(order.getMchId());
        apply.setOpenId(order.getOpenId());
        apply.setOrderId(vo.getOrderId());
        apply.setOrderSn(vo.getOrderSn());
        apply.setOrderType(order.getOrderType());
        apply.setOrderCtime(order.getCtime());
        apply.setOrderPayTime(order.getPaymentTime());

        apply.setMemberId(order.getMemberId());
        apply.setMemberUsername(order.getMemberUsername());
        apply.setMemberPhone(order.getMemberPhone());

        // 商品信息
        apply.setGoodsId(goods.getId());
        apply.setGoodsSkuId(goods.getSkuId());
        apply.setGoodsSkuName(goods.getSkuName());
        apply.setGoodsSkuImg(goods.getSkuPic());
        apply.setGoodsSkuBrand(goods.getSpuBrand());
        apply.setGoodsSkuAttrsVals(goods.getSkuAttrsVals());
        apply.setGoodsSkuCount(goods.getSkuNum());
        apply.setGoodsSkuPrice(goods.getSkuPrice());
        apply.setGoodsSkuRealPrice(goods.getRealAmount());

        apply.setPostSaleSn(postSaleSn);
        apply.setReturnType(3);
        apply.setReturnAmount(goods.getRealAmount());
        apply.setReturnReason(vo.getReturnReason());
        apply.setReturnDescription(vo.getReturnDescription());
        apply.setReturnDescPics(vo.getReturnDescPics());
        apply.setStatus(0);

        final MallDeliveryAddress defaultAddress = this.mallDeliveryAddressService.getDefaultAddress(2);
        if (null != defaultAddress) {
            apply.setReceiveMan(defaultAddress.getName());
            apply.setReceiveAddress(defaultAddress.getDetailAddress());
            apply.setReceivePhone(defaultAddress.getPhone());
        }

        super.save(apply);

        // 修改订单的是否退款为：申请退款
        this.omsOrderService.changeIsRefund(order.getId(), 1);

        // 修改退款商品的退款状态
        goods.setIsRefund(2);
        this.omsOrderGoodsService.updateById(goods);

        // 操作记录
        OmsOrderOperateLog history = new OmsOrderOperateLog();
        history.setOrderId(apply.getId());
        history.setOrderStatus(5);
        history.setOperateUser(umsMember.getNickname());
        history.setOperateType("会员申请退款");
        this.omsOrderOperateLogService.save(history);

        return apply;
    }

    @Override
    public void reject(OmsOrderReturnApplyVo vo) {
        // 商家拒绝申请
        this.changeReturnStatus(vo.getId(), 1);

        final SysUserVo userVo = LoginUserInterceptor.loginUser.get();
        OmsOrderOperateLog history = new OmsOrderOperateLog();
        history.setOrderId(vo.getId());
        history.setOrderStatus(6);
        history.setOperateUser(userVo.getUsername());
        history.setOperateType("商家拒绝");
        history.setOperateContent(vo.getRejectReason());
        this.omsOrderOperateLogService.save(history);
    }

    @Override
    public R agree(OmsOrderReturnApplyVo vo) {
        // 同意退款

        final MallDeliveryAddress defaultAddress = this.mallDeliveryAddressService.getDefaultAddress(2);

        if (null == defaultAddress) {
            return R.failure("未设置默认收货地址");
        }

        final OmsOrderReturnApply apply = super.getById(vo.getId());
        apply.setReceiveMan(defaultAddress.getName());
        apply.setReceivePhone(defaultAddress.getPhone());
        apply.setReceiveAddress(defaultAddress.getDetailAddress());
        apply.setStatus(2);

        super.updateById(apply);

        final SysUserVo userVo = LoginUserInterceptor.loginUser.get();
        OmsOrderOperateLog history = new OmsOrderOperateLog();
        history.setOrderId(vo.getId());
        history.setOrderStatus(7);
        history.setOperateUser(userVo.getUsername());
        history.setOperateType("同意退款");
        this.omsOrderOperateLogService.save(history);

        return R.ok();
    }

    @Override
    public void submitExpress(OmsOrderReturnApplyVo vo) {

        // 会员提交快递信息
        final OmsOrderReturnApply apply = super.getById(vo.getId());
        apply.setExpressNum(vo.getExpressNum());
        apply.setStatus(3);
        super.updateById(apply);

        final UmsMember member = this.umsMemberService.getById(vo.getMemberId());

        OmsOrderOperateLog history = new OmsOrderOperateLog();
        history.setOrderId(vo.getId());
        history.setOrderStatus(8);
        history.setOperateUser(member.getNickname());
        history.setOperateType("会员提交快递信息");
        this.omsOrderOperateLogService.save(history);
    }

    @Override
    public void rejectGoods(OmsOrderReturnApplyVo vo) {
        // 商家拒收货
        this.changeReturnStatus(vo.getId(), 4);

        final SysUserVo userVo = LoginUserInterceptor.loginUser.get();
        OmsOrderOperateLog history = new OmsOrderOperateLog();
        history.setOrderId(vo.getId());
        history.setOrderStatus(9);
        history.setOperateUser(userVo.getUsername());
        history.setOperateType("商家拒收货");
        history.setOperateContent(vo.getRejectReason());
        this.omsOrderOperateLogService.save(history);
    }

    @Override
    public void confirmGoods(OmsOrderReturnApplyVo vo) {
        // 商家确认收货
        this.changeReturnStatus(vo.getId(), 5);

        final SysUserVo userVo = LoginUserInterceptor.loginUser.get();
        OmsOrderOperateLog history = new OmsOrderOperateLog();
        history.setOrderId(vo.getId());
        history.setOrderStatus(10);
        history.setOperateUser(userVo.getUsername());
        history.setOperateType("商家确认收货");
        this.omsOrderOperateLogService.save(history);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R refund(OmsOrderReturnApplyVo vo) {
        // 商家发起退款（立即退款）
        log.info("========================>微信退款<========================");
        log.info("==>商家发起退款");
        log.info("==>发起时间：{}", LocalDateTime.now());

        // 退款申请信息
        final OmsOrderReturnApply refund = super.getById(vo.getId());

        // 申请退款订单
        final OmsOrder order = this.omsOrderService.getOrderByOrderSn(refund.getOrderSn());

        // 退款金额不能大于退款商品的实际支付金额
        if (vo.getConfirmReturnAmount().compareTo(refund.getGoodsSkuRealPrice()) == 1) {
            log.info("==>退款失败：退款金额大于退款商品的实际支付金额");
            return R.failure("退款金额不能大于退款商品的实际支付金额");
        }

        // 构建微信退款数据
        WxPayRefundRequest request = new WxPayRefundRequest();
        request.setOutRefundNo(refund.getPostSaleSn());
        request.setAppid(order.getAppId());
        request.setMchId(order.getMchId());
        request.setTransactionId(order.getTransactionId());
        request.setOutTradeNo(order.getOrderSn());
        request.setTotalFee(AmountUtils.changeY2F(vo.getConfirmReturnAmount()));
        request.setRefundFee(AmountUtils.changeY2F(vo.getConfirmReturnAmount()));

        log.info("退款订单编号：{}", refund.getPostSaleSn());
        log.info("订单编号：{}", order.getOrderSn());
        log.info("订单ID：{}", order.getId());
        log.info("微信支付订单号：{}", order.getTransactionId());
        log.info("商品实际支付金额：{}", refund.getGoodsSkuRealPrice());
        log.info("商品退款金额：{}", vo.getConfirmReturnAmount());

        try {
            final WxPayService wxPayService = WxPayConfiguration.getPayService(order.getAppId());
            WxPayRefundResult result = wxPayService.refund(request);

            if (result.getReturnCode().equals("SUCCESS")) {
                log.info("退款状态：成功");
                // 交易状态：成功
                if (result.getResultCode().equals("SUCCESS")) {
                    // 将退款申请状态修改为：已退款
                    refund.setStatus(6);
                    super.updateById(refund);

                    // 修改订单状态：关闭订单
                    order.setStatus(4);
                    this.omsOrderService.updateById(order);

                    // 资金流水（退款）
                    this.saveFmsFlowFundInfo(result, order, refund);

                    ////////////////////////////////////////////////////////////
                    // 业务处理
                    // 回滚库存
                    // 该订单如果有佣金的话，用户退款成功后，需要将佣金扣除，不转入个人账户
                    ////////////////////////////////////////////////////////////

                    // 获取分销订单的冻结金额记录，修改冻结状态为：已取消（无需到个人账户上）
                    List<FmsMemberCommisionFreeze> freezes = this.fmsMemberCommisionFreezeService.getFreezeByOrderSn(order.getOrderSn());
                    for (FmsMemberCommisionFreeze freeze : freezes) {
                        // 状态：1->待到账，2->已到账，3->锁定（用户申请退款，防止退款时间超过14天），4->已取消(用户14天内申请退款，佣金扣除不到账)
                        freeze.setStatus(3);
                        this.fmsMemberCommisionFreezeService.updateById(freeze);
                    }


                    log.info("==>回滚代理商库存");
                    // 获取订单的商品
                    final List<OmsOrderGoods> goodsList = this.omsOrderGoodsService.getGoodsByOrderSn(order.getOrderSn());

                    for (OmsOrderGoods goods : goodsList) {
                        if (order.getShipType() == 2) {
                            // 回滚代理商库存（递减）
                            this.wmsWareSkuService.getStockDecrease(order.getAgentId(), goods.getSkuId(), goods.getSkuNum());

                            log.info("回滚代理商库存==》SkuId：{} 商品：{}, 回滚数量：{}", goods.getSkuId(), goods.getSkuName(), goods.getSkuNum());
                        }


                        // 回滚系统库存
                        PmsSku sku = this.pmsSkuService.getById(goods.getSkuId());
                        if (null != sku) {
                            sku.setStockNum(sku.getStockNum() + goods.getSkuNum());
                            this.pmsSkuService.updateById(sku);
                            log.info("回滚系统库存==》SkuId：{} 商品：{}, 回滚数量：{}", goods.getSkuId(), goods.getSkuName(), goods.getSkuNum());
                        } else {
                            log.info("商品不存在，SKU_ID=[{}]，商品名=[{}]", goods.getSkuId(), goods.getSkuName());
                        }
                    }


                    final SysUserVo userVo = LoginUserInterceptor.loginUser.get();
                    OmsOrderOperateLog history = new OmsOrderOperateLog();
                    history.setOrderId(vo.getId());
                    history.setOrderStatus(11);
                    history.setOperateUser(userVo.getUsername());
                    history.setOperateType("退款成功");
                    this.omsOrderOperateLogService.save(history);
                }
            } else {
                log.info("退款状态：失败->{}, {}", result.getReturnCode(), result.getResultCode());
                throw new BizException("退款失败");
            }
        } catch (WxPayException e) {
            log.info("微信退款异常：{}", e.getReturnMsg());
            throw new BizException("微信退款异常：" + e.getReturnMsg());
        }
        return R.ok();
    }

    /**
     * 资金流水
     * @param result
     * @param order
     */
    private void saveFmsFlowFundInfo(WxPayRefundResult result, OmsOrder order, OmsOrderReturnApply refund) {

        FmsFinanceCashFlow cashFlow = new FmsFinanceCashFlow();
        cashFlow.setOpenId(order.getOpenId());
        cashFlow.setAppId(order.getOpenId());
        cashFlow.setMchId(order.getMchId());
        cashFlow.setMemberId(order.getMemberId());
        cashFlow.setMemberName(order.getMemberUsername());
        cashFlow.setTransactionId(result.getTransactionId());

        cashFlow.setOrderId(order.getId());
        cashFlow.setOrderSn(order.getOrderSn());
        cashFlow.setGoodsId(refund.getGoodsId());
        cashFlow.setGoodsSkuId(refund.getGoodsSkuId());
        cashFlow.setRefundId(refund.getId());
        cashFlow.setRefundSn(refund.getPostSaleSn());

        // 退款订单
        cashFlow.setTransactionType(2);
        cashFlow.setAmount(refund.getGoodsSkuRealPrice());
        cashFlow.setRemarks("退款商品：" + refund.getGoodsSkuName());

        Map<String, Object> extraMap = new HashMap<String, Object>();
        cashFlow.setExtraJson(JSON.toJSONString(extraMap));

        this.fmsFinanceCashFlowService.save(cashFlow);

    }

    /**
     * 保存支付信息
     * @param result
     * @param order
     */
    //private void saveFinanceInfo(WxPayRefundResult result, OmsOrder order, OmsOrderReturnApply refund) {
    //    FmsFinance finance = new FmsFinance();
    //    finance.setType(3);
    //    finance.setOpenId(order.getOpenId());
    //    finance.setAppId(result.getAppid());
    //    finance.setMchId(result.getMchId());
    //    finance.setMemberId(order.getMemberId());
    //    finance.setMemberName(order.getMemberUsername());
    //    finance.setRefundId(refund.getId());
    //    finance.setRefundSn(refund.getPostSaleSn());
    //    finance.setOrderId(order.getId());
    //    finance.setOrderSn(result.getOutTradeNo());
    //    finance.setTransactionId(result.getTransactionId());
    //    finance.setAmount(order.getPayAmount());
    //    finance.setDescription(order.getPaymentBody());
    //
    //    this.fmsFinanceService.save(finance);
    //}

}